//框架构造函数：执行初始化,对data执行响应化处理
function defineReactive(obj, key, val) {
    //递归
    observe(val)
    // 创建一个Dep和当前key一一对应
    const dep = new Dep()
    //对传入的obj进行拦截访问
    Object.defineProperty(obj, key, {
        get() {
            console.log(`get ${key}:${val}`);
            // 依赖收集在这里
            Dep.target && dep.addDep(Dep.target)
            return val
        },
        set(newVal) {
            if (newVal != val) {
                //如果传入的newVal依旧是对象，也需要做响应化处理
                observe(newVal)
                console.log(`set ${key}:${newVal}`);
                val = newVal
                // 通知更新
                dep.notify()
            }
        }
    })
}
function observe(obj) {
    if (typeof obj !== 'object' || obj == null) { return }
    new Observer(obj)
}

class Observer {
    constructor(value) {
        this.value = value
        this.walk(value)
    }
    walk(obj) {
        Object.keys(obj).forEach(key => { defineReactive(obj, key, obj[key]) })
    }
}
class Zvue {
    constructor(options) {
        this.$options = options
        this.$data = options.data
        observe(this.$data)
        // 为$data做代理
        this.proxy(this, "$data")
        console.log(`this`, this)
        // 创建编译器
        new Compiler(options.el, this)
    }
    proxy(vm) {
        Object.keys(vm.$data).forEach(key => {
            Object.defineProperty(vm, key, {
                get() {
                    return vm.$data[key]
                },
                set(newVal) {
                    vm.$data[key] = newVal
                }
            })
        })
    }
}

// const watchers = [];//临时用于保存watcher测试用
// 监听器：负责更新视图
class Watcher {
    constructor(vm, key, updateFn) {
        // kvue实例 
        this.vm = vm;
        // 依赖key 
        this.key = key;
        // 更新函数 
        this.updateFn = updateFn;
        // 临时放入watchers数组 
        // watchers.push(this)
        // Dep.target静态属性上设置为当前watcher实例
        Dep.target = this
        this.vm[this.key] // 读取触发了getter然后触发了依赖收集到了deps里面
        Dep.target = null // 收集完就置空
    }
    // 更新 
    update() {
        this.updateFn.call(this.vm, this.vm[this.key]);
    }
}

// Dep：依赖，管理某个key相关所有Watcher实例
class Dep {
    constructor() {
        this.deps = []
    }
    addDep(dep) {
        this.deps.push(dep)
    }
    notify() {
        this.deps.forEach(dep => dep.update())
    }
}


